package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
)

func getDirs(dirPath string) ([]string, error) {
	dirs := []string{}

	dir, err := ioutil.ReadDir(dirPath)
	if err != nil {
		fmt.Errorf("read dirt err %v", err)
		return nil, err
	}

	for _, fi := range dir {
		if fi.IsDir() { // 目录, 递归遍历
			dirs = append(dirs, filepath.Join(dirPath, fi.Name()))
		}
	}

	return dirs, nil
}

type pid_io struct {
	Meta map[string]string
}

func main() {
	//travel /proc/{pid}
	dirs, err := getDirs("/proc")
	if err != nil {
		return
	}

	pid_ios := []pid_io{}

	//data scrub
	for _, v := range dirs {
		content, err := os.ReadFile(filepath.Join(v, "io"))
		if err != nil {
			continue
		}

		lines := strings.Split(string(content), "\n")
		p := pid_io{Meta: make(map[string]string)}

		p.Meta["pid"] = strings.TrimPrefix(v, "/proc/")

		for _, l := range lines {

			strs := strings.Split(l, ":")
			if len(strs) == 2 {

				if strs[0] != "read_bytes" && strs[0] != "write_bytes" {
					continue
				}

				p.Meta[strs[0]] = strings.TrimSpace(strs[1])
			} else {
				fmt.Errorf("err file %v content %v", v, l)
			}
		}

		content, err = os.ReadFile(filepath.Join(v, "cmdline"))
		if err != nil {
			continue
		}

		p.Meta["cmdline"] = strings.TrimSuffix(string(content), "\n")

		pid_ios = append(pid_ios, p)

	}

	sort.Slice(pid_ios, func(i, j int) bool {
		r1, _ := strconv.Atoi(pid_ios[i].Meta["read_bytes"])
		r2, _ := strconv.Atoi(pid_ios[j].Meta["read_bytes"])

		return r1 > r2
	})

	//output
	fmt.Printf("order by read_bytes:\n")
	for n, v := range pid_ios {
		if n > 20 {
			break
		}
		fmt.Printf("pid: %10s read_bytes: %-20s write_bytes: %-20s cmdline: %s\n", v.Meta["pid"], v.Meta["read_bytes"], v.Meta["write_bytes"], v.Meta["cmdline"])
	}

	sort.Slice(pid_ios, func(i, j int) bool {
		r1, _ := strconv.Atoi(pid_ios[i].Meta["write_bytes"])
		r2, _ := strconv.Atoi(pid_ios[j].Meta["write_bytes"])

		return r1 > r2
	})

	//output
	fmt.Printf("order by write_bytes:\n")
	for n, v := range pid_ios {
		if n > 20 {
			break
		}

		fmt.Printf("pid: %10s read_bytes: %-20s write_bytes: %-20s cmdline: %s\n", v.Meta["pid"], v.Meta["read_bytes"], v.Meta["write_bytes"], v.Meta["cmdline"])
	}

}
